﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Runtime.Serialization;
using System.Collections.Specialized;
using System.IO;
using System.Web;

using System.Configuration;
using System.Threading;

namespace OAuth
{
    internal class OAuthRequest
    {
        private HttpWebRequest webRequest;
        public OAuthRequest(OAuthMessage message)
        {
            this.Initialize(message);
        }

        public OAuthResponse GetResponse()
        {
            if (this.webRequest == null)
            {
                throw new ApplicationException("OAuthRequst Object is not constructed!");
            }
            HttpWebResponse response = (HttpWebResponse)this.webRequest.GetResponse();
            return new OAuthResponse(response);
        }

        public void BeginGetResponse(Action<OAuthResponse> action)
        {
            this.webRequest.BeginGetResponse(
                delegate(IAsyncResult ar)
                {
                    HttpWebResponse response =
                        (HttpWebResponse)((WebRequest)ar.AsyncState).EndGetResponse(ar);

                    if (action != null)
                    {
                        action(new OAuthResponse(response));
                    }
                }, this.webRequest);
        }

        private void Initialize(OAuthMessage message)
        {
            // create Request object
            webRequest = (HttpWebRequest)WebRequest.Create(message.Uri);

            // !important
            // close continue-100
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.Method = message.HttpMethod.ToString();

            //webRequest.Proxy = new WebProxy(
            //WebProxy proxy = new WebProxy("10.171.100.10", 8080);
            //proxy.Credentials = new NetworkCredential("qwang", "Winson==2004");
            //webRequest.Proxy = proxy;

            // add headers
            IDictionary<string, string> headers = message.HttpHeaders;

            if (headers != null)
            {
                this.SetHeaders(webRequest, headers);
            }

            // write the content
            if (message.HttpMethod == OAuthHttpMethod.POST
                || message.HttpMethod == OAuthHttpMethod.PUT)
            {
                byte[] postData = message.PostBytes;
                if (postData != null)
                {
                    webRequest.ContentLength = postData.Length;
                    using (Stream stream = webRequest.GetRequestStream())
                    {
                        stream.Write(postData, 0, postData.Length);
                    }
                }
            }
        }

        /// <summary>
        /// Set the headers from message, but some of them can not be set in the request object
        /// such as Content-Type, Content-Length, because these are pre-defined as the property of request object,
        /// so the method should filter them.
        /// </summary>
        /// <param name="webRequest">the target request object</param>
        /// <param name="headers">headers from message</param>
        private void SetHeaders(HttpWebRequest webRequest, IDictionary<string, string> headers)
        {
            foreach (string key in headers.Keys)
            {
                if (string.IsNullOrEmpty(webRequest.Headers[key]))
                {
                    switch (key)
                    {
                        // filter
                        case "Content-Type":
                            webRequest.ContentType = headers[key];
                            break;
                        case "Content-Length":
                            continue;
                        /*
                        long defaultLength = 0;
                        webRequest.ContentLength =
                            long.TryParse(headers[key], out defaultLength) ? defaultLength : 0L;
                        break;
                         */
                        default:
                            webRequest.Headers[key] = headers[key];
                            break;
                    };
                }
            }
        }
    }
}
